闲话 22.10.8

闲话

突然感觉好久没翻译东西了
所以拿今天这题的题面复健一下
果然还是在翻译的时候感觉很爽

好的今天又来了一道SA模板
然而我仍然不会
扔了个 O(n2logn) 的排序上去,随便写了个很丑的暴力lcp匹配
90pts
优化了lcp的匹配
100pts
我不理解 这数据真就拿脚造呗

被推荐了一道题
[省选联考 2021 B 卷] 取模
“在已知CCF连续两年D1T1的数据是拿脚随的的情况下”是这么说的
“我们充分发扬人类智慧”是这么说的
“根据数学直觉,取最大 6 个点匹配,”是这么A的
我不理解 这数据真就拿脚造呗

分断を生んじゃった椅子取りゲーム 無痛分娩で授かるベイブ

壮大な内輪ノリを歴史と呼ぶ

生きたいが死ねと言われ 死にたいが生きろと言われ

生きたいが死ねと言われ 死にたいが生きろと言われ

幸せ自慢はダメ? 不幸嘆いてもダメ?

杂题

CF896D

拉琪旭喜欢拍电影,所以奈芙莲帮她开了一家电影院。我们可以叫它 No.68 电影院。

然而,有一天,No.68 电影院没有零钱了(她们当前没有 50 元钞票),但是奈芙莲仍然想要把电影院开下去。(这里假定“元”是悬浮大陆群的一种货币。)

现在有三种顾客:第一种带来了 50 元钞票,刚好够买一张电影票;第二种带来了 100 元钞票,而奈芙莲需要找给他/她 50 元钞票零钱;最后一种有 VIP 卡,所以她们不需要花钱。

现在有 n 个顾客在电影院门口排队。奈芙莲想知道有多少种可能的排队方案,使得他们能被顺序接待(即所有顾客都能得到找零),而且接待完所有顾客后剩余的 50 元钞票数量在 [l,r] 之间。两种排队方案不同当且仅当存在一个顾客在两种方案中的种类不同。由于答案可能很大,请输出对 p 取模的值。

0lrn105,p2×109保证 p 是质数。

组合题。
抽象题面,序列计数,元素取值 {1,0,1},满足任意位置前缀和非负,总和 [l,r]

首先考虑 p 是质数的时候怎么做。这时我们发现可以预处理阶乘来算组合数了。
考虑答案怎么算。

我们发现 0 对答案没用,于是可以枚举 0 的个数 c0,算出剩下的 (nc0) 个数的答案后乘入 (nc0) 即可。然后考虑剩下的取值 {1,1} 的元素怎么算。
设非 0 数的数量为 i1 的数量与 1 的数量之差(答案)为 j,则立得 1 的数量为 i+j21 的数量为 ij2
抽象操作。我们设序列是二维格点上的操作序列,1 为向左走 1 距离,1 为向上走 1,则答案即为不越过 y=x,从 (0,0)(i+j2,ij2) 的所有操作序列。根据卡特兰数结论,容易发现答案是

(ii+j2)(ii+j2+1)

证明

由于从 (0,0)(i+j2,ij2) 的所有操作序列数量为 (ii+j2),只需证明越过 y=x,从 (0,0)(i+j2,ij2) 的所有操作序列数量为 (ii+j2+1) 即可。

由于这玩意是卡特兰相关,考虑一个对称。
我们发现,越过 y=x 的路径定会交 l:y=x+1 于至少一个点。考虑将交点及之后的所有部分路径关于 l 作对称,则我们得到了一系列到达 (i+j2,ij2) 关于 l 的对称点 (i+j2+1,ij21) 的路径。

容易发现对于所有不合法的路径,一定可以被包含在交 l 的路径上,而合法路径一定不会被包含在其中。于是对不合法路径的计数即为自 (0,0)(i+j2+1,ij21) 的路径数,即

(ii+j2+1)

证毕。

因此答案即为

i=0n(ni)(j=lr(ii+j2)(ii+j2+1))

注意由于 i+j21 的个数,为整数,因此需要使得 i,j 的奇偶性相同。

我们发现后面那部分的求和号可以展开使得每两项之间正负和为 0,于是可以展开。记第一个与 i 奇偶性相同的 jjl,最后一个为 jr,立得

i=0n(ni)((ii+jl2)(ii+jr2+1))

于是可以在 O(n) 复杂度内算得答案。

但是我们是不是忘记了点什么……p 不是质数啊(笑

根据唯一分解定理,记

p=i=1kpici,ci>0

显然有 k9

对于每个数 x,我们都可以将其表为 x×piαi,其中 xpαi0
于是在这种表示法下,乘除法是简便的:乘法只需要将互质部分相乘再模 pp 质因子的指数相加;逆元可以通过欧拉定理得到,指数相减。然而加减法是不得当的,但是我们不用加减法。

预处理每个数字的表示法,在计算时按正常公式计算阶乘与组合数即可。
获取答案时直接使用快速幂乘入质数部分即可。

此方法的复杂度是 O(nk) 的,由于 k9,因此可以快速得到答案。
使用光速幂做到 O(1) 计算,我们有最坏时间复杂度 O(nlogp)

code
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
#define int long long
#define rep(i,a,b) for (register int (i) = (a); (i) <= (b); ++(i))
#define pre(i,a,b) for (register int (i) = (a); (i) >= (b); --(i))
const int N = 1e5 + 10;
int n, mod, ans, l, r, t1, t2;
int phi, phi_1, fact[15], tot[15], cnt;

typedef long long ll; typedef __int128 lll;
struct FastMod { int m; ll b; void init(int _m) { m = _m; b = ((lll)1<<64) / m; } int operator() (ll a) {ll q = ((lll)a * b) >> 64; a -= q * m; if (a >= m) a -= m; return a; } } Mod;
int add(ll a, int b) { return (a += b) >= mod ? a - mod : a; } int mul(int a, int b) { return Mod(1ll * a * b); } template <typename ...Args> int mul(int a, Args ...b) { return mul(a, mul(b...)); }

int qp(int a, int b) {
    int ret = 1;
    while (b) {
        if (b & 1) ret = mul(a, ret);
        a = mul(a, a);
        b >>= 1;
    } return ret;
}

struct Light {
    int p, c, sq, dsq[1000], usq[1000];
    void init(int _p, int _c) {
        p = _p, c = _c;
        sq = sqrt(_c) + 1;
        dsq[0] = usq[0] = 1;
        rep(i,1,sq-1) dsq[i] = mul(dsq[i-1], p);
        usq[1] = mul(dsq[sq-1], p);
        rep(i,2,sq) usq[i] = mul(usq[i], usq[1]);
    }
    int qp(int c) {
        return mul(dsq[c % sq], usq[c / sq]);
    }
} qpow[15];

struct Int {
    int arg, inv, c[15];

    Int() { arg = inv = 1; memset(c, 0, sizeof c); }

    Int(int k) {
        register int d;
        rep(i,1,cnt) {
            d = k / fact[i];
            c[i] = 0;
            while (d * fact[i] == k) c[i]++, k = d, d = k / fact[i];
            tot[i] = max(tot[i], c[i]);
        } k %= mod;
        arg = k; inv = qp(arg, phi_1);
    }

    Int operator = (const Int & a) {
        arg = a.arg, inv = a.inv;
        rep(i,1,cnt) c[i] = a.c[i];
        return *this;
    } 

    Int operator * (const Int & b) const {
        register Int ret;
        ret.arg = mul(arg, b.arg);
        ret.inv = mul(inv, b.inv);
        rep(i,1,cnt) ret.c[i] = c[i] + b.c[i], tot[i] = max(tot[i], ret.c[i]);
        return ret;
    }

    Int operator / (const Int & b) const {
        register Int ret;
        ret.arg = mul(arg, b.inv);
        ret.inv = mul(inv, b.arg);
        rep(i,1,cnt) ret.c[i] = c[i] - b.c[i];
        return ret;
    }

    int get_val() {
        register int ret = arg;
        rep(i,1,cnt) ret = mul(ret, qpow[i].qp(c[i]));
        return ret;
    }
} Factor[N];

int C(int a, int b) {
    if (a < b) return 0;
    return (Factor[a] / Factor[b] / Factor[a - b]).get_val();
}

signed main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n >> mod >> l >> r;
    Mod.init(mod);
    t1 = mod, phi = mod;
    for (register int i = 2; i * i <= t1; i++) {
        if (t1 % i == 0) {
            fact[++cnt] = i;
            phi = phi / i * (i-1);
            while (t1 % i == 0) t1 /= i;
        } 
    } if (t1 > 1) fact[++cnt] = t1, phi = phi / t1 * (t1 - 1);
    phi_1 = phi - 1;
    Factor[0] = Int(1);
    rep(i,1,n) Factor[i] = Factor[i-1] * Int(i);
    register int ret = 0, lb, rb, tans;
    rep(i,1,cnt) qpow[i].init(fact[i], tot[i]);
    rep(i,l,n) {
        lb = l;
        ((lb^i) & 1) ? (++lb) : (0);
        rb = min(i, r);
        ((lb^i) & 1) ? (--lb) : (0);
        if (lb > rb) continue;
        tans = add(C(i, (i + lb) >> 1), mod - C(i, (i + rb + 2) >> 1));
        tans = mul(tans, C(n, i));
        ans = add(ans, tans);
    } cout << ans << endl;
}
posted @   joke3579  阅读(72)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示